package com.xyy.saas.payment.adpater.fumin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.xyy.saas.payment.adpater.fumin.config.CertConstants;
import com.xyy.saas.payment.adpater.fumin.spring.SpringConfiguration;
import com.xyy.saas.payment.adpater.fumin.spring.SpringConfiguration2;
import com.xyy.saas.payment.adpater.fumin.util.VerifyAndDecryptUtil;
import com.xyy.saas.payment.adpater.fumin.util.VerifyAndDecryptUtil2;
import com.xyy.saas.payment.adpater.pingxx.domain.*;
import com.xyy.saas.payment.callback.core.handler.CastRequestHandler;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.enums.FBankTradeStatusEnum;
import com.xyy.saas.payment.cores.enums.FBankPowerIdEnum;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.util.DateUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.util.Map;
import java.util.TreeMap;

/**
 * @Author: wuqiongda
 * @Date: 2019/12/17 19:14
 */
@Component
public class CastYBMFMRequestHandler implements CastRequestHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(CastYBMFMRequestHandler.class);

    @Autowired
    private SpringConfiguration springConfiguration;
    @Autowired
    private SpringConfiguration2 springConfiguration2;

    @Override
    public String getChannel() {
        return Constants.CHANNEL_YBM_FUMIN_BANK_NAME;
    }

    @Override
    public Object castRequestHandler(String method, Map<String, String> request, HttpServletRequest requestMsg) throws Exception {
        switch (method) {
            case Constants.METHOD_PAY_SUCCESS_NAME:
                return castToPayDO(request);
            case Constants.METHOD_REFUND_SUCCESS:
                return castToRefundDO(request);
            case Constants.METHOD_WITHDRAW_NAME:
                return castToWithdrawalDO(request);
            default:
                break;
        }

        return null;
    }

    private PayDO castToPayDO(Map<String, String> requestMsg) throws Exception {
        Map<String, String> params = JSONObject.parseObject(
                requestMsg.get("post-val"), new TypeReference<TreeMap<String, String>>() {});

        //商户订单号
        String payNo = params.get("mchntOrderNo");
        String tradeNo = params.get("orderNo");
        String channel = params.get("description");
        String mchId = params.get("extra");
        Integer amount = Integer.parseInt(params.get("amount"));
        String channelTransactionNo = params.get("bankTransactionId");
        // 转换payMode
        String payPowerId = params.get("payPowerId");
        String payMode = FBankPowerIdEnum.getPayModeByPowerId(payPowerId);
        String tradeTime = params.get("paidTime");

        PayDO domain = new PayDO();
        domain.setOrderNo(payNo);
        domain.setChannelChargeNo(tradeNo);
        domain.setAmount(amount);
        domain.setChannel(Constants.CHANNEL_FUMIN_BANK_NAME+"_"+channel);
        domain.setPayMode(payMode);
        domain.setMchId(mchId);
        domain.setResultCode("SUCCESS");
        domain.setChannelTransactionNo(channelTransactionNo);

        try {
            if(!StringUtils.isBlank(tradeTime)) {
                domain.setTimePaid(DateUtil.parase(tradeTime, DateUtil.YYYYMMDDHHMMSS));
            }
        }
        catch(Exception e) {
            LOGGER.error("CastYBMFMRequestHandler#castToPayDo cast time error request:{}", JSON.toJSONString(requestMsg));
        }

        return domain;
    }

    private RefundDO castToRefundDO(Map<String, String> requestMsg) throws Exception {
        RefundDO domain = new RefundDO();

        try {
            Map<String, Object> map = JSONObject.parseObject(
                    requestMsg.get("post-val"), new TypeReference<TreeMap<String, Object>>() {});
            JSONObject json = new JSONObject(map);
            String signResult = VerifyAndDecryptUtil.decryptResult(json, springConfiguration.privateKey());
            JSONObject jsonObject =JSONObject.parseObject(signResult);
            LOGGER.info("CastYBMFMRequestHandler#castToRefundDO result:{}", jsonObject.toJSONString());

            //商户订单号
            String refundNo = jsonObject.getString("bizChannelOrderid");
            domain.setRefundNo(refundNo);
            /**
             * 0-处理中
             * 1-成功
             * 2-失败
             */
            String tradeStatus = jsonObject.getString("tradeStatus");
            domain.setSucceed(true);

            if(!"1".equals(tradeStatus)) {
                domain.setSucceed(false);
                domain.setStatus(RefundOrder.STATUS_FAIL);
            }

            //第三方退款单号
            domain.setId(jsonObject.getString("tradeNo"));
            domain.setTimeSucceed(DateUtil.parase(jsonObject.getString("finishTime"),DateUtil.DATEFORMATSECOND));
        }
        catch(Exception e){
            LOGGER.error("CastChinaBankRequestHandler.castToRefundDO error：" + e.getMessage() + ", requestMsg:" + requestMsg,e);
        }

        return domain;
    }

    /**
     * 提现对象
     */
    private WithdrawalDO castToWithdrawalDO(Map<String, String> request) throws Exception {
        String body = request.get("post-val");
        Map<String, Object> map = JSONObject.parseObject(body, new TypeReference<TreeMap<String, Object>>() {});
        boolean v2 = body.contains(CertConstants.ALGORITHM_RSAV2);
        JSONObject json = v2 ? JSONObject.parseObject((String) map.get("data")) : new JSONObject(map);
        String signResult = v2 ?
                VerifyAndDecryptUtil2.get().verifyAndDecrypt(springConfiguration2, json) :
                VerifyAndDecryptUtil.decryptResult(json, springConfiguration.privateKey());
        JSONObject jsonObject = JSONObject.parseObject(signResult);

        WithdrawalDO domain = new WithdrawalDO();
        domain.setId(v2 ? jsonObject.getString("bizNo") : jsonObject.getString("tradeNo"));
        domain.setWithdrawNo(v2 ? jsonObject.getString("merchantOrderNo") : jsonObject.getString("bizChannelOrderid"));
        domain.setExtra(jsonObject.getString("tradeRemark"));

        if(v2) {
            String errorMsg = jsonObject.getString("errorMsg");
            String remittanceReason = jsonObject.getString("remittanceReason");
            domain.setFailureMsg(errorMsg + remittanceReason);
        }
        else {
            domain.setFailureMsg(jsonObject.getString("msg"));
        }

        domain.setFee(0);
        domain.setStatus(getTradeStatus(jsonObject.getString("tradeStatus")));

        if("succeeded".equals(domain.getStatus())) {
            domain.setTimeSucceeded(DateUtil.sdf1ToDate(jsonObject.getString("finishTime")));
        }

        return domain;
    }

    private String getTradeStatus(String channelStatus) {
        if(channelStatus == null || "2".equals(channelStatus) || FBankTradeStatusEnum.FAILURE.name().equals(channelStatus)) {
            return "failed";
        }

        if("1".equals(channelStatus) || FBankTradeStatusEnum.SUCCESS.name().equals(channelStatus)) {
            return "succeeded";
        }

        if("15".equals(channelStatus) || FBankTradeStatusEnum.RE_EXCHANGED.name().equals(channelStatus)) {
            return "refund";
        }

        return "failed";
    }
}

